#include <rtthread.h>
#include <rtdevice.h>

#include "spl06_01.h"

#define HW_ADR 0x77

#define ADC_DEV_NAME "spl06"
#define DBG_TAG "spl06"
#define DBG_LVL DBG_INFO

#include <rtdbg.h>
static void spl0601_get_calib_param(spl0601_t* hdev);
struct spl06_register_map spl06_regs = { 0 };

uint8_t spl06_spi_read(spl0601_t* hdev, uint8_t regadr, uint8_t* data, uint8_t len)
{
    /**
     * @brief Reading is done by lowering CSB and first sending one control byte.
     * The control bytes consist of the SPI register address (= full register address without bit 7)
     * and the read command (bit7=RW=’1’). After writing the control byte,
     * data is sent out of the SDO pin (SDA in 3-wire mode);
     * the register address is automatically incremented.
     *
     */
    struct rt_spi_message msg1, msg2;
    regadr |= 0x80;
    msg1.send_buf = &regadr;
    msg1.recv_buf = RT_NULL;
    msg1.length = 1;
    msg1.cs_take = 1;
    msg1.cs_release = 0;
    msg1.next = &msg2;

    msg2.send_buf = RT_NULL;
    msg2.recv_buf = data;
    msg2.length = len;
    msg2.cs_take = 0;
    msg2.cs_release = 1;
    msg2.next = RT_NULL;
    rt_spi_transfer_message(hdev->bus, &msg1);
    return RT_EOK;
}
/**
 * @brief
 *
 * @param hdev
 * @param regadr
 * @param data
 * @param len
 * @return uint8_t
 */
uint8_t spl06_spi_write(spl0601_t* hdev, uint8_t regadr, uint8_t* data, uint8_t len)
{
    /**
     * @brief Writing is done by lowering CSB and sending pairs control bytes and register data.
     * The control bytes consist of the SPI register address (=full register address without bit 7)
     * and the write command (bit7=RW=’0’). Several pairs can be written without raising CSB.
     * The transaction is ended by a raising CSB.
     *
     */
    // regadr &= 0x7F;
    struct rt_spi_message msg1, msg2;
    msg1.send_buf = &regadr;
    msg1.recv_buf = RT_NULL;
    msg1.length = 1;
    msg1.cs_take = 1;
    msg1.cs_release = 0;
    msg1.next = &msg2;

    msg2.send_buf = data;
    msg2.recv_buf = RT_NULL;
    msg2.length = len;
    msg2.cs_take = 1;
    msg2.cs_release = 1;
    msg2.next = RT_NULL;
    rt_spi_transfer_message(hdev->bus, &msg1);
    return RT_EOK;
}

uint8_t spl06_write_reg(spl0601_t* hdev, uint8_t reg, uint8_t val)
{
    return spl06_spi_write(hdev, reg, &val, 1);
}
uint8_t spl06_read_reg(spl0601_t* hdev, uint8_t reg)
{
    uint8_t val;
    spl06_spi_read(hdev, reg, &val, 1);
    return val;
}

int spl0601_init(spl0601_t* hdev, const char* busname)
{
#if defined(SPL0601_BUS_MODE_SPI)
    hdev->bus = (struct rt_spi_device*)rt_device_find(busname);
    hdev->bus->config.data_width = 8;
    hdev->bus->config.mode = RT_SPI_MASTER | RT_SPI_MSB | RT_SPI_MODE_3;
    hdev->bus->config.max_hz = 10 * 1000 * 100;
    rt_spi_configure(hdev->bus, &(hdev->bus->config));//NOTE 调用config后才会开始设置
#elif defined(SPL0601_BUS_MODE_I2C)
    hdev->bus = rt_i2c_bus_device_find(busname);
#endif
    if (hdev->bus == RT_NULL)
    {
        return -1;
    }
    hdev->i32rawPressure = 0;
    hdev->i32rawTemperature = 0;
    spl0601_get_calib_param(hdev);
    hdev->chip_id = spl06_read_reg(hdev,SPL0601_REG_ID);
    if(hdev->chip_id == 0x10)
    {
        LOG_I("Product and Revision ID: 0x%02X",hdev->chip_id);
    }
    spl06_temperature_rate_set(hdev, PT_MEASUREMENT_RATE_4, PT_OVERSAMPLE_RATE_1);
    spl06_pressure_rate_set(hdev, PT_MEASUREMENT_RATE_128, PT_OVERSAMPLE_RATE_4);

    return 0;
}


const int32_t OversamplingRateScaleFactor_kT_kT[8] = {
    524288,// 1 (single) 
    1572864,// 2 times (Low Power) 
    3670016,// 4 times 
    7864320,// 8 times 
    253952,// 16 times (Standard) 
    516096,// 32 times 
    1040384,// 64 times (High Precision) 
    2088960,// 128 times 
};
/**
 * @brief set pressure measurement rate and oversample rate
 *
 * @param hdev
 * @param pm measurement rate
 * @param prc oversample rate
 */
void spl06_pressure_rate_set(spl0601_t* hdev, enum spl06_measurement_rate pm, enum spl06_oversample_rate prc)
{
    if (pm <= PT_MEASUREMENT_RATE_128)
    {
        spl06_regs.prs_cfg_bit.PM_RATE = pm;
    }
    if (prc <= PT_OVERSAMPLE_RATE_128)
    {
        hdev->i32kP = OversamplingRateScaleFactor_kT_kT[prc];
        spl06_regs.prs_cfg_bit.PM_PRC = prc;
        if (prc > PT_OVERSAMPLE_RATE_8)
        {
            spl06_regs.cfg_reg_bit.P_SHIFT = 1;
        }
    }
    LOG_D("PRS_CFG:%02X, CFG_REG:%02X, i32kP:%d,", spl06_regs.PRS_CFG, spl06_regs.CFG_REG, hdev->i32kP);
    spl06_write_reg(hdev, SPL0601_REG_PRS_CFG, spl06_regs.PRS_CFG);
    spl06_write_reg(hdev, SPL0601_REG_CFG_REG, spl06_regs.CFG_REG);
    LOG_D("rPRS_CFG:%02X",spl06_read_reg(hdev, SPL0601_REG_PRS_CFG));
}
/**
 * @brief set temperature measurement rate and oversample rate
 *
 * @param hdev
 * @param pm measurement rate
 * @param prc oversample rate
 */
void spl06_temperature_rate_set(spl0601_t* hdev, enum spl06_measurement_rate pm, enum spl06_oversample_rate prc)
{
    if (pm <= PT_MEASUREMENT_RATE_128)
    {
        spl06_regs.tmp_cfg_bit.PM_RATE = pm;
        spl06_regs.tmp_cfg_bit.TMP_EX = 1;//NOTE 温度不对时，必须要用这个！！！
    }
    if (prc <= PT_OVERSAMPLE_RATE_128)
    {
        hdev->i32kT = OversamplingRateScaleFactor_kT_kT[prc];
        spl06_regs.tmp_cfg_bit.PM_PRC = prc;
        if (prc > PT_OVERSAMPLE_RATE_8)
        {
            spl06_regs.cfg_reg_bit.T_SHIFT = 1;
        }
    }
    LOG_D("TMP_CFG:%02X, CFG_REG:%02X, i32kT:%d,", spl06_regs.TMP_CFG, spl06_regs.CFG_REG, hdev->i32kT);
    spl06_write_reg(hdev, SPL0601_REG_TMP_CFG, spl06_regs.TMP_CFG);
    spl06_write_reg(hdev, SPL0601_REG_CFG_REG, spl06_regs.CFG_REG);
    LOG_D("rTMP_CFG:%02X",spl06_read_reg(hdev, SPL0601_REG_TMP_CFG));
}

static void spl0601_get_calib_param(spl0601_t* hdev)
{
    //NOTE 结构体直接接收处理COEF数据流！！！
    uint8_t raw[20] = { 0 };
    while (1)
    {
        spl06_regs.MEAS_CFG = spl06_read_reg(hdev, SPL0601_REG_MEAS_CFG);
        if(spl06_regs.meas_cfg_bit.COEF_RDY)
        {
            break;
        }
        LOG_W("waiting for coef ready %02X...",spl06_regs.MEAS_CFG);
        rt_thread_delay(10);
    }
    
    spl06_spi_read(hdev, SPL0601_REG_COEF, raw, 18);
    // union spl06_coef coef = { 0 };
    LOG_D("Raw: ");
    for (int i = 0;i < 18;i++)//NOTE 大小数据端重新对齐一下
    {
        // rt_kprintf("%02X ",raw[i]);
        hdev->calib_param.coef[i] = raw[17 - i];
    }
    LOG_D("\ncoef:%d \n", sizeof(coef));
    LOG_D("c0: 0x%08X, %d\n", hdev->calib_param.c0,hdev->calib_param.c0);
    LOG_D("c1: 0x%08X, %d\n", hdev->calib_param.c1,hdev->calib_param.c1);
    LOG_D("c00:0x%08X, %d\n", hdev->calib_param.c00,hdev->calib_param.c00);
    LOG_D("c10:0x%08X, %d\n", hdev->calib_param.c10,hdev->calib_param.c10);
    LOG_D("c01:0x%08X, %d\n", hdev->calib_param.c01,hdev->calib_param.c01);
    LOG_D("c11:0x%08X, %d\n", hdev->calib_param.c11,hdev->calib_param.c11);
    LOG_D("c20:0x%08X, %d\n", hdev->calib_param.c20,hdev->calib_param.c20);
    LOG_D("c21:0x%08X, %d\n", hdev->calib_param.c21,hdev->calib_param.c21);
    LOG_D("c30:0x%08X, %d\n", hdev->calib_param.c30,hdev->calib_param.c30);
    hdev->calib_param.c0 = hdev->calib_param.c0;
    hdev->calib_param.c1 = hdev->calib_param.c1;
    hdev->calib_param.c00 = hdev->calib_param.c00;
    hdev->calib_param.c10 = hdev->calib_param.c10;
    hdev->calib_param.c01 = hdev->calib_param.c01;
    hdev->calib_param.c11 = hdev->calib_param.c11;
    hdev->calib_param.c20 = hdev->calib_param.c20;
    hdev->calib_param.c21 = hdev->calib_param.c21;
    hdev->calib_param.c30 = hdev->calib_param.c30;
}

void spl0601_start_temperature(spl0601_t* hdev)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = MEAS_CTRL_TEMPERATURE_MEASUREMENT;
    LOG_D("MEAS_CFG(%02X):%02X", SPL0601_REG_MEAS_CFG, spl06_regs.MEAS_CFG);
    spl06_write_reg(hdev,SPL0601_REG_MEAS_CFG,spl06_regs.MEAS_CFG);
}

void spl0601_start_pressure(spl0601_t* hdev)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = MEAS_CTRL_PRESSURE_MEASUREMENT;
    LOG_D("MEAS_CFG(%02X):%02X", SPL0601_REG_MEAS_CFG, spl06_regs.MEAS_CFG);
    spl06_write_reg(hdev,SPL0601_REG_MEAS_CFG,spl06_regs.MEAS_CFG);
}

void spl0601_start_continuous(spl0601_t* hdev, uint8_t mode)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = mode;
    LOG_D("regs:%d reg:%d %d\n", sizeof(spl06_regs), sizeof(spl06_regs.MEAS_CFG), spl06_regs.MEAS_CFG);
    spl06_spi_write(hdev, SPL0601_REG_MEAS_CFG, &spl06_regs.MEAS_CFG, 1);
    // switch(mode)
    // {
    //     case SPL06_MODE_WEATHER_STATION:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_2,PT_OVERSAMPLE_RATE_1);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_1,PT_OVERSAMPLE_RATE_1);
    //     break;
    //     case SPL06_MODE_INDOOR_NAVIGATION:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_2,PT_OVERSAMPLE_RATE_16);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_1,PT_OVERSAMPLE_RATE_1);
    //     break;
    //     case SPL06_MODE_SPORTS:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_64);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_1);
    //     break;
    //     default:
    //     spl06_pressure_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_64);
    //     spl06_temperature_rate_set(hdev,PT_MEASUREMENT_RATE_4,PT_OVERSAMPLE_RATE_1);
    //     break;
    // }
}

void spl0601_stop(spl0601_t* hdev)
{
    spl06_regs.MEAS_CFG = 0;
    spl06_regs.meas_cfg_bit.MEAS_CTRL = MEAS_CTRL_STOP;
    LOG_D("regs:%d reg:%d %d\n", sizeof(spl06_regs), sizeof(spl06_regs.MEAS_CFG), spl06_regs.MEAS_CFG);
    spl06_spi_write(hdev, SPL0601_REG_MEAS_CFG, &spl06_regs.MEAS_CFG, 1);
}

void spl0601_get_raw_temp(spl0601_t* hdev)
{
    uint8_t buf[3];
#if defined(SPL0601_BUS_MODE_I2C)
    struct rt_i2c_msg msg;
    msg.addr = HW_ADR;
    msg.buf = &reg;
    msg.len = 1;
    msg.flags = RT_I2C_WR;
    rt_i2c_transfer(hdev->bus, &msg, 1);
    msg.buf = buf;
    msg.len = 3;
    msg.flags = RT_I2C_RD;
    rt_i2c_transfer(hdev->bus, &msg, 1);
#elif defined(SPL0601_BUS_MODE_SPI)
    rt_spi_configure(hdev->bus, &hdev->bus->config);
    spl06_spi_read(hdev, SPL0601_REG_TMP_B2, buf, 3);
#endif
    hdev->i32rawTemperature = (int32_t)buf[0] << 16 | (int32_t)buf[1] << 8 | (int32_t)buf[2];
    hdev->i32rawTemperature = (hdev->i32rawTemperature & 0x800000) ? (0xFF000000 | hdev->i32rawTemperature) : hdev->i32rawTemperature;
    LOG_D("i32rawTemperature:%d", hdev->i32rawTemperature);
}

void spl0601_get_raw_pressure(spl0601_t* hdev)
{
    uint8_t buf[3];
#if defined(SPL0601_BUS_MODE_I2C)
    struct rt_i2c_msg msg;
    msg.addr = HW_ADR;
    msg.buf = &reg;
    msg.len = 1;
    msg.flags = RT_I2C_WR;
    rt_i2c_transfer(hdev->bus, &msg, 1);
    msg.buf = buf;
    msg.len = 3;
    msg.flags = RT_I2C_RD;
    rt_i2c_transfer(hdev->bus, &msg, 1);
#elif defined(SPL0601_BUS_MODE_SPI)
    spl06_spi_read(hdev, SPL0601_REG_PRS_B2, buf, 3);
#endif
    hdev->i32rawPressure = (int32_t)buf[0] << 16 | (int32_t)buf[1] << 8 | (int32_t)buf[2];
    hdev->i32rawPressure = (hdev->i32rawPressure & 0x800000) ? (0xFF000000 | hdev->i32rawPressure) : hdev->i32rawPressure;
    LOG_D("raw pressure = %d, %08X", hdev->i32rawPressure, hdev->i32rawPressure);
}

float spl0601_get_temperature(spl0601_t* hdev)
{
    float fTCompensate;
    float Traw_sc;

    Traw_sc = (float)hdev->i32rawTemperature / (float)hdev->i32kT;
    fTCompensate = hdev->calib_param.c0 * 0.5f + hdev->calib_param.c1 * Traw_sc;
    return fTCompensate;
}
float spl0601_get_pressure(spl0601_t* hdev)
{
    float fTsc, fPsc;
    float qua2, qua3;
    float fPCompensate;

    fTsc = hdev->i32rawTemperature / (float)hdev->i32kT;
    fPsc = hdev->i32rawPressure / (float)hdev->i32kP;
    qua2 = hdev->calib_param.c10 + fPsc * (hdev->calib_param.c20 + fPsc * hdev->calib_param.c30);
    qua3 = fTsc * fPsc * (hdev->calib_param.c11 + fPsc * hdev->calib_param.c21);

    fPCompensate = hdev->calib_param.c00 + fPsc * qua2 + fTsc * hdev->calib_param.c01 + qua3;
    return fPCompensate;
}
